package gamelogic

import (
	"server_cluster/common/config"
	"server_cluster/common/gdconf"
	"server_cluster/common/logger"
	"server_cluster/common/mysock"
	"server_cluster/common/protoc/pb"
	"server_cluster/logic/sharemem"
)

// ==========消息协议处理============

func HomeDataReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_HomeDataReq, new(pb.CS_HomeDataReq), buf, user).(*pb.CS_HomeDataReq)
	if !ok {
		return config.PROTO_ERROR
	}
	_ = req

	pbUnlockBuildingIdList := make([]int32, 0)
	for _, unlockBuilding := range user.GetUnlockBuildingMap() {
		pbUnlockBuildingIdList = append(pbUnlockBuildingIdList, unlockBuilding.BuildingId)
	}
	SendMsg(config.SC_HomeDataRsp, &pb.SC_HomeDataRsp{
		BuildingList:         user.PacketPbBuildingList(),
		UnlockBuildingIdList: pbUnlockBuildingIdList,
		HomeLevel:            int32(user.UserHome.Level),
		HomeExp:              user.UserHome.Exp,
	}, buf, user)

	return config.OK
}

func HomeBuildingEditReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_HomeBuildingEditReq, new(pb.CS_HomeBuildingEditReq), buf, user).(*pb.CS_HomeBuildingEditReq)
	if !ok {
		return config.PROTO_ERROR
	}

	switch req.Type {
	case pb.BuildingEditType_BUILDING_EDIT_BUILD:
		homeBuildingConfig := gdconf.GetHomeBuildingConfig(req.BuildingId)
		if homeBuildingConfig == nil {
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.CONFIG_NOT_FOUND, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		homeBuildingLevelGroupConfig := gdconf.GetHomeBuildingLevelGroupConfigByGroupAndLevel(homeBuildingConfig.BuildingLevelGroup, 1)
		if homeBuildingLevelGroupConfig == nil {
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.CONFIG_NOT_FOUND, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		if homeBuildingConfig.BuildingNumLimit != nil {
			for _, limitConfig := range homeBuildingConfig.BuildingNumLimit {
				if limitConfig[0] != int32(user.UserHome.Level) {
					continue
				}
				currBuildingNum := int32(0)
				for _, building := range user.GetBuildingMap() {
					if building.BuildingId == req.BuildingId {
						currBuildingNum++
					}
				}
				if currBuildingNum >= limitConfig[1] {
					logger.Error("curr building num limit, buildingId: %v, currBuildingNum: %v, uid: %v", req.BuildingId, currBuildingNum, user.GetUid())
					return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.SERVER_ERROR, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
				}
			}
		}
		unlockBuilding := user.GetUnlockBuildingById(req.BuildingId)
		if unlockBuilding == nil {
			logger.Error("building not unlock, buildingId: %v, uid: %v", req.BuildingId, user.GetUid())
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.SERVER_ERROR, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		user.UserHome.AddExp(homeBuildingLevelGroupConfig.AddHomeExp)

		costItemMap := make(map[int32]int32)
		for _, costItem := range homeBuildingLevelGroupConfig.CostItemList {
			costItemMap[costItem.ItemId] += costItem.ItemCount
		}
		ok = CostItems(costItemMap, user)
		if !ok {
			logger.Error("cost item error, costItemMap: %v, uid: %v", costItemMap, user.GetUid())
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.ITEM_NOT_ENOUGH, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		_, ok := user.AddBuilding(req.BuildingId, req.Pos)
		if !ok {
			logger.Error("add building fail, BuildingId: %v, uid: %v", req.BuildingId, user.GetUid())
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.SERVER_ERROR, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_HAVE_HOME_BUILDING_FOR_LEVEL, true)
		SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.OK, BuildingList: user.PacketPbBuildingList(), HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
	case pb.BuildingEditType_BUILDING_EDIT_MOVE:
		building := user.GetBuildingById(req.BuildingUuid)
		if building == nil {
			logger.Error("building not exist, BuildingUuid: %v, uid: %v", req.BuildingUuid, user.GetUid())
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.OBJECT_NOT_FOUND, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		building.PosX = req.Pos.X
		building.PosY = req.Pos.Y
		building.PosZ = req.Pos.Z
		building.SetSync()
		SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.OK, BuildingList: user.PacketPbBuildingList(), HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
	case pb.BuildingEditType_BUILDING_EDIT_DESTROY:
		building := user.GetBuildingById(req.BuildingUuid)
		if building == nil {
			logger.Error("building not exist, BuildingUuid: %v, uid: %v", req.BuildingUuid, user.GetUid())
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.OBJECT_NOT_FOUND, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		homeBuildingConfig := gdconf.GetHomeBuildingConfig(req.BuildingId)
		if homeBuildingConfig == nil {
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.CONFIG_NOT_FOUND, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}
		addItemMap := make(map[int32]int32)
		for level := building.Level; level > 0; level-- {
			homeBuildingLevelGroupConfig := gdconf.GetHomeBuildingLevelGroupConfigByGroupAndLevel(homeBuildingConfig.BuildingLevelGroup, int32(level))
			if homeBuildingLevelGroupConfig == nil {
				continue
			}
			for _, item := range homeBuildingLevelGroupConfig.CostItemList {
				addItemMap[item.ItemId] += item.ItemCount
			}
		}
		for i := 0; i < len(building.Farm.FarmLandList); i++ {
			farmLand := building.Farm.GetFarmLandByIndex(int32(i))
			if farmLand == nil {
				continue
			}
			if farmLand.SeedId == 0 {
				continue
			}
			addItemMap[farmLand.SeedId]++
		}

		ret := AddItems(addItemMap, user)
		if ret != config.OK {
			logger.Error("add item error, ret: %v", ret)
		}
		pConfig := gdconf.GetHomeBuildingLevelGroupConfigByGroupAndLevel(homeBuildingConfig.BuildingLevelGroup, int32(building.Level))
		if pConfig != nil {
			user.UserHome.SubExp(pConfig.AddHomeExp)
		}
		ok = user.DestroyBuilding(req.BuildingUuid)
		if !ok {
			logger.Error("building not exist, BuildingUuid: %v, uid: %v", req.BuildingUuid, user.GetUid())
			return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.OBJECT_NOT_FOUND, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
		}

		SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.OK, BuildingList: user.PacketPbBuildingList(), HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
	default:
		logger.Error("unknown building edit type: %v, uid: %v", req.Type, user.GetUid())
		return SendMsg(config.SC_HomeBuildingEditRsp, &pb.SC_HomeBuildingEditRsp{RetCode: config.SERVER_ERROR, HomeLevel: int32(user.UserHome.Level), HomeExp: user.UserHome.Exp}, buf, user)
	}

	return config.OK
}

func HomeFarmLandOpReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_HomeFarmLandOpReq, new(pb.CS_HomeFarmLandOpReq), buf, user).(*pb.CS_HomeFarmLandOpReq)
	if !ok {
		return config.PROTO_ERROR
	}

	building := user.GetBuildingById(req.FarmBuildingUuid)
	if building == nil {
		logger.Error("建筑对象不存在 %v", req.FarmBuildingUuid)
		SendMsg(config.SC_HomeFarmLandOpRsp, &pb.SC_HomeFarmLandOpRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}

	pbItemList := make([]*pb.Item, 0)
	switch req.Type {
	case pb.FarmLandOpType_FarmLandOpTypeSeed:
		var canPlantNum int32 = 0
		for i := 0; i < len(building.Farm.FarmLandList); i++ {
			farmLand := building.Farm.GetFarmLandByIndex(int32(i))
			if farmLand == nil {
				continue
			}
			if farmLand.SeedId != 0 {
				continue
			}
			canPlantNum++
		}
		costItemMap := make(map[int32]int32)
		costItemMap[req.SeedId] = canPlantNum
		costItemList := AutoFoundItem(costItemMap, user)
		if costItemList == nil {
			logger.Error("auto found item error, costItemMap: %v, uid: %v", costItemMap, user.GetUid())
			SendMsg(config.SC_HomeFarmLandOpRsp, &pb.SC_HomeFarmLandOpRsp{RetCode: config.ITEM_NOT_ENOUGH}, buf, user)
			return config.OK
		}
		SubItems(costItemList, user)
		homeFarmSeedConfig := gdconf.GetHomeFarmSeedConfig(req.SeedId)
		if homeFarmSeedConfig == nil {
			SendMsg(config.SC_HomeFarmLandOpRsp, &pb.SC_HomeFarmLandOpRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
			return config.OK
		}
		for i := 0; i < len(building.Farm.FarmLandList); i++ {
			farmLand := building.Farm.GetFarmLandByIndex(int32(i))
			if farmLand == nil {
				continue
			}
			farmLand.SeedId = req.SeedId
			farmLand.EndTime = sharemem.MyShm.TimeNow + int64(homeFarmSeedConfig.GatherTime)*60
			building.SetSync()
		}
		TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_HOME_SEED, true, 1)
	case pb.FarmLandOpType_FarmLandOpTypeGather:
		itemMap := make(map[int32]int32)
		var finishTimes int32 = 0
		for i := 0; i < len(building.Farm.FarmLandList); i++ {
			var farmLand = &(building.Farm.FarmLandList[i])
			if farmLand == nil {
				continue
			}
			if farmLand.SeedId == 0 {
				continue
			}
			if sharemem.MyShm.TimeNow < farmLand.EndTime {
				continue
			}
			homeFarmSeedConfig := gdconf.GetHomeFarmSeedConfig(farmLand.SeedId)
			if homeFarmSeedConfig == nil {
				continue
			}
			for _, item := range homeFarmSeedConfig.RewardItem {
				itemMap[item.ItemId] += item.ItemCount
			}
			building.Farm.AddFarmGatherHistory(farmLand.SeedId)
			farmLand.MemInit()
			building.SetSync()
			finishTimes++
		}
		TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_HOME_GATHER, true, finishTimes)
		user.TriggerActivityTask(gdconf.ActivityTaskFinishCondHomeGather, finishTimes)
		if len(itemMap) != 0 {
			ret := AddItems(itemMap, user)
			if ret != config.OK {
				logger.Error("添加道具失败 %v", ret)
			}
			for k, v := range itemMap {
				pbItemList = append(pbItemList, &pb.Item{
					Id:  k,
					Num: v,
				})
			}
		}
	case pb.FarmLandOpType_FarmLandOpTypeClear:
		addItemMap := make(map[int32]int32)
		for i := 0; i < len(building.Farm.FarmLandList); i++ {
			farmLand := building.Farm.GetFarmLandByIndex(int32(i))
			if farmLand == nil {
				continue
			}
			if farmLand.SeedId == 0 {
				continue
			}
			addItemMap[farmLand.SeedId]++
			farmLand.MemInit()
			building.SetSync()
		}
		AddItems(addItemMap, user)
	default:
	}

	SendMsg(config.SC_HomeFarmLandOpRsp, &pb.SC_HomeFarmLandOpRsp{RetCode: config.OK, Type: req.Type, FarmBuilding: building.PacketPbBuilding(user), ItemList: pbItemList}, buf, user)
	return config.OK
}

func HomeFactoryOpReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_HomeFactoryOpReq, new(pb.CS_HomeFactoryOpReq), buf, user).(*pb.CS_HomeFactoryOpReq)
	if !ok {
		return config.PROTO_ERROR
	}

	building := user.GetBuildingById(req.FactoryBuildingUuid)
	if building == nil {
		logger.Error("建筑对象不存在 %v", req.FactoryBuildingUuid)
		SendMsg(config.SC_HomeFactoryOpRsp, &pb.SC_HomeFactoryOpRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}
	pbItemList := make([]*pb.Item, 0)
	switch req.Type {
	case pb.HomeFactoryOpType_HomeFactoryOpTypeTakeItem:
		pbItemList = append(pbItemList, &pb.Item{Id: building.Factory.ItemId, Num: building.Factory.CurrItemCount})
		ret := AddItems(map[int32]int32{building.Factory.ItemId: building.Factory.CurrItemCount}, user)
		if ret != config.OK {
			logger.Error("添加道具失败 %v", ret)
		}
		TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_AWARD_ITEM_BY_BUILDING, true, building.Factory.ItemId, building.Factory.CurrItemCount)
		user.TriggerActivityTask(gdconf.ActivityTaskFinishCondHomeAwardItem, building.Factory.CurrItemCount)
		building.Factory.CurrItemCount = 0
		building.Factory.LastTime = sharemem.MyShm.TimeNow
		building.RefreshFactory()
	default:
	}

	SendMsg(config.SC_HomeFactoryOpRsp, &pb.SC_HomeFactoryOpRsp{RetCode: config.OK, Type: req.Type, FactoryBuilding: building.PacketPbBuilding(user), ItemList: pbItemList}, buf, user)
	return config.OK
}

func HomeBuildingUpgradeReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_HomeBuildingUpgradeReq, new(pb.CS_HomeBuildingUpgradeReq), buf, user).(*pb.CS_HomeBuildingUpgradeReq)
	if !ok {
		return config.PROTO_ERROR
	}

	building := user.GetBuildingById(req.BuildingUuid)
	if building == nil {
		logger.Error("建筑对象不存在 %v", req.BuildingUuid)
		SendMsg(config.SC_HomeBuildingUpgradeRsp, &pb.SC_HomeBuildingUpgradeRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}
	homeBuildingConfig := gdconf.GetHomeBuildingConfig(building.BuildingId)
	if homeBuildingConfig == nil {
		SendMsg(config.SC_HomeBuildingUpgradeRsp, &pb.SC_HomeBuildingUpgradeRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	homeBuildingLevelGroupConfig := gdconf.GetHomeBuildingLevelGroupConfigByGroupAndLevel(homeBuildingConfig.BuildingLevelGroup, int32(building.Level))
	if homeBuildingLevelGroupConfig == nil {
		SendMsg(config.SC_HomeBuildingUpgradeRsp, &pb.SC_HomeBuildingUpgradeRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	if homeBuildingLevelGroupConfig.CostItemList == nil {
		logger.Error("已经升到最大等级了")
		SendMsg(config.SC_HomeBuildingUpgradeRsp, &pb.SC_HomeBuildingUpgradeRsp{RetCode: config.SERVER_ERROR}, buf, user)
		return config.OK
	}
	costItemMap := make(map[int32]int32)
	for _, costItem := range homeBuildingLevelGroupConfig.CostItemList {
		costItemMap[costItem.ItemId] += costItem.ItemCount
	}
	ok = CostItems(costItemMap, user)
	if !ok {
		logger.Error("道具不足 %v", costItemMap)
		return SendMsg(config.SC_HomeBuildingUpgradeRsp, &pb.SC_HomeBuildingUpgradeRsp{RetCode: config.ITEM_NOT_ENOUGH}, buf, user)
	}
	oldLevel := building.Level
	building.Level++
	building.SetSync()
	user.UserHome.AddExp(homeBuildingLevelGroupConfig.AddHomeExp)

	SendMsg(config.SC_HomeBuildingUpgradeRsp, &pb.SC_HomeBuildingUpgradeRsp{
		RetCode:   config.OK,
		OldLevel:  int32(oldLevel),
		NewLevel:  int32(building.Level),
		Building:  building.PacketPbBuilding(user),
		HomeLevel: int32(user.UserHome.Level),
		HomeExp:   user.UserHome.Exp,
	}, buf, user)
	return config.OK
}
